package com.lulin.mall.ware.service.impl;

import com.lulin.common.dto.SkuHasStockDTO;
import com.lulin.common.exception.NoStockExecption;
import com.lulin.common.utils.R;
import com.lulin.mall.ware.fegin.ProductFeignService;
import com.lulin.mall.ware.vo.OrderItemVo;
import com.lulin.mall.ware.vo.WareSkuLockVo;
import lombok.Data;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lulin.common.utils.PageUtils;
import com.lulin.common.utils.Query;

import com.lulin.mall.ware.dao.WareSkuDao;
import com.lulin.mall.ware.entity.WareSkuEntity;
import com.lulin.mall.ware.service.WareSkuService;
import org.springframework.transaction.annotation.Transactional;


@Service("wareSkuService")
public class WareSkuServiceImpl extends ServiceImpl<WareSkuDao, WareSkuEntity> implements WareSkuService {

    @Autowired
    private WareSkuDao wareSkuDao;

    @Autowired
    private ProductFeignService productFeignService;

    /**
     * 根据条件，查询商品库存
     *
     * @param params
     * @return
     */
    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        QueryWrapper<WareSkuEntity> wrapper = new QueryWrapper<>();
        //查询条件  商品sku_id
        String skuId = (String) params.get("skuId");
        if (!StringUtils.isEmpty(skuId)) {
            wrapper.eq("sku_id", skuId);
        }
        //仓库id
        String wareId = (String) params.get("wareId");
        if (!StringUtils.isEmpty(wareId)) {
            wrapper.eq("ware_id", wareId);
        }
        //分页查询
        IPage<WareSkuEntity> page = this.page(
                new Query<WareSkuEntity>().getPage(params),
                wrapper
        );
        return new PageUtils(page);
    }

    /**
     * 采购的入库操作
     *
     * @param skuId  商品ids
     * @param wareId 库存id
     * @param skuNum 采购的商品数量
     */
    @Override
    public void addStock(Long skuId, Long wareId, Integer skuNum) {
        //1、判断是否有该商品、和仓库的入库记录
        List<WareSkuEntity> list = wareSkuDao.selectList(new QueryWrapper<WareSkuEntity>()
                .eq("sku_id", skuId).eq("ware_id", wareId));
        //没有，就新增商品库存记录；
        if (list == null || list.size() == 0) {
            WareSkuEntity entity = new WareSkuEntity();
            entity.setSkuId(skuId);
            entity.setWareId(wareId);
            entity.setStock(skuNum);
            entity.setStockLocked(0);//锁定库存

            //动态的设置商品的名称——跨服务的——pms_sku_info
            try {
                R info = productFeignService.info(skuId);
                Map<String, Object> skuInfo = (Map<String, Object>) info.get("skuInfo");
                if (info.getCode() == 0) {
                    entity.setSkuName((String) skuInfo.get("skuName"));
                }
            } catch (Exception e) {

            }

            //插入操作
            wareSkuDao.insert(entity);
        } else {
            //有，根据商品id和库存id，更新库存
            wareSkuDao.updateStock(skuId, wareId, skuNum);
        }
    }

    /**
     * 获取每个skuId对应的库存
     *
     * @param skuIds 商品skuId
     * @return
     */
    @Override
    public List<SkuHasStockDTO> getSkusHasStock(List<Long> skuIds) {
        List<SkuHasStockDTO> list = skuIds.stream().map(skuId -> {
            //根据skuId，查询对应的库存信息（库存-锁定库存）
            Long count = baseMapper.getSkuStock(skuId);
            SkuHasStockDTO dto = new SkuHasStockDTO();
            dto.setSkuId(skuId);
            dto.setHasStock(count > 0);
            return dto;
        }).collect(Collectors.toList());

        return list;
    }

    /**
     * 锁定订单库存操作
     * —— 真实的开发，应该是锁定离用户最近的仓库的库存
     */
    @Transactional
    @Override
    public Boolean orderLockStock(WareSkuLockVo vo) {
        List<OrderItemVo> itemVos = vo.getItemVos();
        //1、找到有库存的仓库
        List<SkuWareHasStock> skuWareHasStocks = itemVos.stream().map(item -> {
            SkuWareHasStock wareHasStock = new SkuWareHasStock();
            wareHasStock.setSkuId(item.getSkuId());
            //根据skuId，查询出哪些仓库有库存
            List<WareSkuEntity> wareSkuEntities = this.baseMapper.listHasStock(item.getSkuId());
            wareHasStock.setWareSkuEntities(wareSkuEntities);
            wareHasStock.setNum(item.getCount());
            return wareHasStock;
        }).collect(Collectors.toList());

        //尝试锁定库存
        for (SkuWareHasStock skuWareHasStock : skuWareHasStocks) {
            Long skuId = skuWareHasStock.getSkuId();
            List<WareSkuEntity> wareSkuEntities = skuWareHasStock.wareSkuEntities;
            if (wareSkuEntities == null && wareSkuEntities.size() == 0) {
                //表示当前商品没有库存了
                throw new NoStockExecption(skuId);
            }
            // 当前需要锁定的商品的数量
            Integer count = skuWareHasStock.getNum();
            Boolean skuStocked = false; // 表示当前SkuId的库存没有锁定完成
            for (WareSkuEntity wareSkuEntity : wareSkuEntities) {
                // 循环获取到对应的 仓库，然后需要锁定库存
                //有可能一个仓库锁定的数量，大于库存数
                //获取当前仓库可用锁定的库存数
                Integer canStock = wareSkuEntity.getStock() - wareSkuEntity.getStockLocked();
                if (count <= canStock) {
                    //表示当前的skuId的商品的数量 <= 需要锁定的数量
                    //根据skuId,wareId，更新锁定库存
                    Integer row = this.baseMapper.lockSkuStock(skuId, wareSkuEntity.getWareId(), count);//影响行数
                    count = 0;
                    skuStocked = true;
                } else {
                    //说明 需要锁定的库存 》 可以锁定的库存，就按照已有的库存来锁定
                    Integer row = this.baseMapper.lockSkuStock(skuId, wareSkuEntity.getWareId(), canStock);//影响行数
                    count = count - canStock;
                }
                if (count <= 0) {
                    //表示 索引的商品都锁定了
                    break;
                }
            }
            if (count > 0) {
                //说明库存没有锁定完
                throw new NoStockExecption(skuId);
            }
            if (skuStocked == false) {
                // 表示上一个商品没有锁定库存成功
                throw new NoStockExecption(skuId);
            }
        }
        return true;
    }

    /**
     * 是否有库存的对象
     */
    @Data
    class SkuWareHasStock {
        private Long skuId;
        private Integer num;
        private List<WareSkuEntity> wareSkuEntities;

    }
}
